import uuid
from datetime import timedelta, datetime
from io import BytesIO

from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.db import connection
from django.http import JsonResponse
from django.shortcuts import render, redirect
import minio
from django.template.loader import render_to_string
from django.utils import timezone
from ebisu import ebisu

from mypaper import settings
from paper.models import Question, ExerciseRecord, TestRecord, Doc

MINIO_SERVER = settings.MINIO_SERVER
PAPER_BUCKET = 'my-paper'

courses = ['语文', '数学', '英语', '物理', '化学', '政治', ]


# 首页
def index_view(request):
    return render(request, 'paper/index.html', {'courses': courses})


# #提交，保存题目
def post(request):
    if request.method == 'POST':
        ret = {'status': False}
        file_list = ['question', 'answer', 'analyze']
        file_uploaded = {}
        p = request.POST

        course = p['course']
        title = p['title']
        question_type = p['type']

        try:
            client = minio.Minio(MINIO_SERVER, 'minioadmin', 'minioadmin', secure=False)
            if not client.bucket_exists(PAPER_BUCKET):
                client.make_bucket(PAPER_BUCKET)

            for file in file_list:
                if file in request.FILES:
                    file_request = request.FILES[file]
                    _, file_ext = file_request.name.split('.')
                    f = BytesIO()
                    for c in file_request.chunks():
                        f.write(c)

                    # 写入minio
                    f.seek(0)
                    f_size = f.getbuffer().nbytes
                    file_name = '%s.%s' % (uuid.uuid1(), file_ext)
                    obj = client.put_object(PAPER_BUCKET, file_name, data=f, length=f_size)
                    file_uploaded[file] = file_name
            # 记录
            Question.objects.create(
                course=course,
                subject=p['subject'],
                title=title,
                question=file_uploaded['question'],
                question_type=question_type,
                answer=file_uploaded['answer'] if 'answer' in file_uploaded.keys() else '',
                analyze=file_uploaded['analyze'] if 'analyze' in file_uploaded.keys() else '',
            )
            # print(file_uploaded)
            ret['status'] = True
        except Exception as e:
            print(e)
            ret['err'] = str(e)
        return JsonResponse(ret)


# qs 返回 题目列表
def make_questions(qs):
    client = minio.Minio(MINIO_SERVER, 'minioadmin', 'minioadmin', secure=False)
    records = [{
        'pk': q.id,
        'question': client.presigned_get_object(PAPER_BUCKET, q.question, expires=timedelta(days=1)),
        'answer': '' if q.answer == ''
        else client.presigned_get_object(PAPER_BUCKET, q.answer, expires=timedelta(days=1)),
        'analyze': '' if q.analyze == ''
        else client.presigned_get_object(PAPER_BUCKET, q.analyze, expires=timedelta(days=1)),
    } for q in qs]
    return records


# 取问题分类
def get_subjects(question_type):
    qs = Question.objects.filter(question_type=question_type).distinct('subject')
    a = [[q.subject, q.course] for q in qs]
    values = set(map(lambda x: x[1], a))
    return [{'title': x, 'subjects': [y[0] for y in a if y[1] == x]} for x in values]


# 练习
def exercise_view(request):
    if request.method == 'POST':
        course = request.POST['course']
        subject = request.POST['subject']
        qs = Question.objects.filter(question_type='问题', course=course, subject=subject).order_by('-id')
        html = ''
        if qs.count() > 0:
            records = make_questions(qs)
            html = render_to_string('paper/exercise_partial.html', {'records': records})
        return JsonResponse({'html': html})
    # 取subject
    subjects = get_subjects('问题')
    return render(request, 'paper/exercise.html', {'courses': courses, 'subjects': subjects})


# # 提交保存练习结果
def post_exercise(request):
    ret = {'success': False}
    if request.method == 'POST':
        marked = False
        if 'mark0' in request.POST:
            marked = True
        try:
            ex = ExerciseRecord.objects.create(
                question=Question.objects.get(pk=int(request.POST['question_id'])),
                cost=int(request.POST['time_cost']),
                mark=marked,
                user=request.user
            )
            ret['success'] = True
        except Exception as e:
            ret['err'] = str(e)
        print('已记录%s' % request.POST['question_id'])
    return JsonResponse(ret)


# 统计
def statistics_view(request):
    pass


# 记忆
@login_required
def recall_view(request):
    if request.method == 'POST':
        tag, id_recall = request.POST['recall'].split('_')
        try:
            obj = TestRecord.objects.get(question=int(id_recall))
            obj.total += 1  # 记录总数
            if tag == 'success':
                obj.successes += 1  # 记录成功数
            obj.recall = 100
            # obj.test_last = timezone.now()
            # 计算更新 α、β、t
            model = (obj.alpha, obj.beta, obj.t)
            one = timedelta(hours=1)
            now = datetime.now()
            # success 不再用1
            model_new = ebisu.updateRecall(model, obj.successes, obj.total, (now - obj.last_test) / one)
            obj.alpha = round(model_new[0], 2)
            obj.beta = round(model_new[1], 2)
            obj.t = round(model_new[2], 2)
            # 保存
            obj.save()
        except TestRecord.DoesNotExist:
            success = 0
            if tag == 'success':
                success += 1  # 记录成功数
            TestRecord.objects.create(
                question=Question.objects.get(pk=id_recall),
                user=request.user,
                successes=success,
                total=1,
                recall=100,
            )

        return JsonResponse({'status': True})

    client = minio.Minio(MINIO_SERVER, 'minioadmin', 'minioadmin', secure=False)
    # 过滤关键字
    course = ''
    subject = ''
    if request.method == 'GET':
        if 'course' in request.GET.keys():
            course = request.GET['course']
        if 'subject' in request.GET.keys():
            subject = request.GET['subject']
    # 取未测试记录， 概念
    with connection.cursor() as cursor:
        sql = '''select a.id from paper_question as a left join paper_testrecord as b on a.id = b.question_id  
                       where b.question_id is null and question_type=\'概念\''''
        if course != '':
            sql += " and a.course='%s'" % course
        if subject != '':
            sql += " and a.subject='%s'" % subject
        cursor.execute(sql)
        row_ids = [q[0] for q in cursor.fetchall()]
        # print('未同步', row_ids)

        sql = 'select id from paper_question where id in (select question_id from paper_testrecord where recall <= 50)' \
              ' and question_type=\'概念\''
        if course != '':
            sql += " and course='%s'" % course
        if subject != '':
            sql += " and subject='%s'" % subject

        cursor.execute(sql)
        row_ids2 = [q[0] for q in cursor.fetchall()]
        # print('小于50的', row_ids2)

        row_ids = row_ids + row_ids2
        qs = Question.objects.filter(pk__in=row_ids)

        records = make_questions(qs)

    subjects = get_subjects('概念')
    # 取易忘记的记录

    return render(request, 'paper/recall.html',
                  {'qs': records, 'course': course, 'subjects': subjects, 'subject': subject})


# 文档
def doc_view(request):
    if request.method == 'POST':
        ret = {'success': False}
        file = request.FILES['qqfile']
        name, ext = file.name.split('.')
        # 读文件到内存
        f = BytesIO()
        for c in file.chunks():
            f.write(c)

        try:
            # 写文件到s3
            f.seek(0)
            raw_size = f.getbuffer().nbytes

            file_date = datetime.strftime(datetime.now(), '%Y%m%d%H%M%S')
            file_name = '%s-%s.%s' % (name, file_date, ext)
            client = minio.Minio(MINIO_SERVER, access_key='minioadmin', secret_key='minioadmin', secure=False)
            etag = client.put_object(PAPER_BUCKET, file_name, data=f, length=raw_size)
            # 存储到数据表
            obj = Doc.objects.create(
                course=request.POST['course'],
                title=request.POST['title'],
                brief=request.POST['brief'],
                bucket=PAPER_BUCKET,
                filename=file_name
            )
            ret['success'] = True
        except Exception as e:
            ret['err'] = '错误：' + str(e)

        return JsonResponse(ret)

    return render(request, 'paper/document.html')


# 课程的文档
def docs_of_course(request):
    if request.method == 'POST':
        ret = {'success': False, 'data': []}
        c = request.POST['course']
        qs = Doc.objects.filter(course=c).order_by('-created')
        if qs.count() > 0:
            data = [{'id': q.id, 'title': q.title, 'brief': q.brief, 'created': datetime.strftime(q.created, '%Y/%m%d')}
                    for q in qs]
            ret['data'] = data
            ret['success'] = True
        return JsonResponse(ret)
    if request.method == 'GET':
        if 'id' in request.GET:
            qs = Doc.objects.get(id=request.GET['id'])
            client = minio.Minio(MINIO_SERVER, access_key='minioadmin', secret_key='minioadmin', secure=False)
            url = client.presigned_get_object(PAPER_BUCKET, qs.filename, expires=timedelta(days=1))
            return redirect(url)
